useImperativeHandle と forwardRef を使うととても便利
hooks 出てきた頃に「使うのはコーナーケースなので〜」というようなことが書いてあったのでスルーしていたのだけど、ついに使うタイミングがきた
素直に React のアプリ書いてるとユースケースは確かになさそうなのだけど モーダルで使う機能を hook に切り出している
モーダルの開け閉めをする関数をモーダルのコンポーネントが持っている
親ページでモーダルの開け閉めをするために子の開け閉め関数を呼びたい
というシーンで使えることが分かった
子コンポーネントでは forwardRef で ref を受け取って useImperativeHandle を使って、モーダル開け閉め用の関数を指定する
親コンポーネント側で useRef を使って ref を作って、子に ref={ref} で渡す
親コンポーネントで ref.current から参照する
少しハマったのは、onClick={ref.current ? ref.current.foo : undefined} みたいな感じに書くと ref の更新で render が走らないっぽいので foo を参照できない
onClick={() => ref.current ? ref.current.foo() : undefined} にするとクリックしたタイミングで評価されるので参照できる
具体的なコードは
code:App.tsx
interface Handler {
foo(): void
}
const Child = forwardRef<Handler, Props>(props, ref) => {
const { foo } = useSome()
useImperativeHandler(ref, () => {
foo: () => foo()
}))
return <div>...</div>
}
const App: React.FC = () => {
const childRef = useRef({} as Handler)
return (
<div>
<button onClick={() => childRef.current ? childRef.current.foo() : null}>click me</button>
<Child ref={childRef} />
</div>
)
}
参考: